/*
* The MIT License
*
* Copyright (c) 2010-2012, Manufacture Française des Pneumatiques Michelin,
* Thomas Maurel, Romain Seguy, Sun Microsystems, Inc., Kohsuke Kawaguchi,
* Martin Eigenbrodt, Tom Huybrechts, Yahoo!, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.michelin.cio.hudson.plugins.qc;
import hudson.Extension;
import hudson.FilePath.FileCallable;
import hudson.Launcher;
import hudson.AbortException;
import hudson.matrix.MatrixAggregatable;
import hudson.matrix.MatrixAggregator;
import hudson.matrix.MatrixBuild;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.BuildListener;
import hudson.model.Project;
import hudson.model.Result;
import hudson.remoting.VirtualChannel;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;
import hudson.tasks.junit.TestResult;
import hudson.tasks.junit.TestResultAction;
import hudson.tasks.test.TestResultAggregator;
import hudson.tasks.test.TestResultProjectAction;
import org.apache.tools.ant.DirectoryScanner;
import org.kohsuke.stapler.DataBoundConstructor;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* This class is adapted from {@link JunitResultArchiver}; Only the {@code perform()}
* method slightly differs.
*
* @author Thomas Maurel
*/
public class QualityCenterResultArchiver extends Recorder implements Serializable, MatrixAggregatable {
@DataBoundConstructor
public QualityCenterResultArchiver() {
}
@Override
public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
TestResultAction action;
List<Builder> builders = ((Project)build.getProject()).getBuilders();
final List<String> names = new ArrayList<String>();
// Get the TestSet report files names of the current build
for(Builder builder : builders) {
if(builder instanceof QualityCenter) {
List<String> files = ((QualityCenter) builder).getTestSetLogFiles();
if(files != null && files.size() > 0) { // log files may not have been generated
names.addAll(((QualityCenter) builder).getTestSetLogFiles());
}
}
}
// Has any QualityCenter builder been set up?
if(names.isEmpty()) {
listener.getLogger().println(Messages.QualityCenterResultArchiver_NoBuilderSet());
return true;
}
try {
final long buildTime = build.getTimestamp().getTimeInMillis();
final long nowMaster = System.currentTimeMillis();
TestResult result = build.getWorkspace().act(new FileCallable<TestResult>() {
public TestResult invoke(File ws, VirtualChannel channel) throws IOException {
final long nowSlave = System.currentTimeMillis();
List<String> files = new ArrayList<String>();
DirectoryScanner ds = new DirectoryScanner();
ds.setBasedir(ws);
// Transform the report file names list to a File Array,
// and add it to the DirectoryScanner includes set
for(String name : names) {
if(name != null) { // JENKINS-12389
File file = new File(ws, name);
if(file.exists()) {
files.add(file.getName());
}
}
}
Object[] objectArray = new String[files.size()];
files.toArray(objectArray);
ds.setIncludes((String[])objectArray);
ds.scan();
if(ds.getIncludedFilesCount()==0) {
// no test result. Most likely a configuration error or fatal problem
throw new AbortException("Report not found");
}
return new TestResult(buildTime+(nowSlave-nowMaster), ds, true);
}
});
action = new TestResultAction(build, result, listener);
if(result.getPassCount()==0 && result.getFailCount()==0) {
throw new AbortException("Result is empty");
}
} catch (AbortException e) {
if(build.getResult()==Result.FAILURE) {
// most likely a build failed before it gets to the test phase.
// don't report confusing error message.
return true;
}
listener.getLogger().println(e.getMessage());
build.setResult(Result.FAILURE);
return true;
} catch (IOException e) {
e.printStackTrace(listener.error("Failed to archive QC reports"));
build.setResult(Result.FAILURE);
return true;
}
build.getActions().add(action);
if(action.getResult().getFailCount()>0) {
build.setResult(Result.UNSTABLE);
}
return true;
}
@Override
public Action getProjectAction(AbstractProject<?, ?> project) {
return new TestResultProjectAction(project);
}
public MatrixAggregator createAggregator(MatrixBuild build, Launcher launcher, BuildListener listener) {
return new TestResultAggregator(build,launcher,listener);
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.BUILD;
}
@Extension
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
public String getDisplayName() {
return Messages.QualityCenterResultArchiver_DisplayName();
}
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
}
}